Preservation bugfix to put PreserveExpiryTime whenever machine transitions to Failed phase - #1147
Preservation bugfix to put PreserveExpiryTime whenever machine transitions to Failed phase#1147r4mek wants to merge 8 commits into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
/kind bug |
thiyyakat
left a comment
There was a problem hiding this comment.
Thanks for the changes and the refactoring! I haven't looked at the full PR yet. I had one case in mind for which I thought the new code may not behave as expected. Once you address that, I will look at the rest as well.
| defer trackers.Stop() | ||
| waitForCacheSync(stop, c) | ||
| err := c.updateMachineAndMachineDeploymentDeletionAnnotations(context.TODO(), testMachineDeployment) | ||
| err := func() error { |
There was a problem hiding this comment.
This may be a stupid question, but what is the point of the closure here? Can you not simply have just L2361?
| node.Annotations[PreserveMachineAnnotationKey]; ok && | ||
| AllowedPreserveAnnotationValues.Has(val) { | ||
| return val, true |
There was a problem hiding this comment.
Please print a warning here if the value is not valid.
| if val, ok := | ||
| machine.Annotations[PreserveMachineAnnotationKey]; ok && | ||
| AllowedPreserveAnnotationValues.Has(val) { | ||
| return val, true |
There was a problem hiding this comment.
Please log a warning if the value is not valid.
| preserveAnnotationValue, exists := machineutils.GetPreserveAnnotationValue(node, machine) | ||
| if !exists { | ||
| return | ||
| } else if getErr != nil { | ||
| if !apierrors.IsNotFound(getErr) { | ||
| err = getErr | ||
| return | ||
| } | ||
| klog.Warningf("Couldn't find node %q for machine %q", nodeName, machine.Name) | ||
| err = nil | ||
| } |
There was a problem hiding this comment.
Please correct me if I'm wrong, but what about the case where preservation was being manipulated by only the machine object's annotations? If a machine was preserved, and the annotation was deleted to indicate that preservation should be stopped, you will end up returning early here instead of stopping preservation.
There was a problem hiding this comment.
Good catch! Addressed in the latest commit ab6bf44
gagan16k
left a comment
There was a problem hiding this comment.
Thanks for the changes! Have some comments, PTAL
| }) | ||
| updatedMachine, err := machineutils.PatchMachine(ctx, c.Machines(machine.Namespace), &machine, func(m *v1alpha1.Machine) error { | ||
| m.Labels = labelsutil.AddLabel(m.Labels, v1alpha1.DefaultMachineDeploymentUniqueLabelKey, hash) | ||
| return nil |
There was a problem hiding this comment.
This will force a reconcile instead of retry on returning 409 errors, so the unit test for LDRCBST could flake even more now. Might need to find another way to correct that.
There was a problem hiding this comment.
After our offline discussions, the error is very low and honestly I am not really sure why the LDRCBST test is failed. More investigation would be required for fixing it and not sure whether we want to tackle it now.
| // Deep-copy to avoid mutating cache objects downstream. | ||
| for i, m := range filteredMachines { | ||
| filteredMachines[i] = m.DeepCopy() | ||
| } | ||
|
|
There was a problem hiding this comment.
Great change, but I was thinking if we could apply this while creating the filteredMachines slices, in claimMachines().
Argument for: Saves extra work on the slice, and does it in the same loop while the slice is getting constructed.
Argument against: The other callers for the function, do not seem to write to the slice like this reconciler does, and thus do not really need a deep copy. WDYT?
There was a problem hiding this comment.
I did not implement it in claimMachines() for the reason mentioned in Argument against. But if the team sees differently, I can implement it.
aaronfern
left a comment
There was a problem hiding this comment.
General feedback
- Newly introduced flag should be mentioned in description and release notes
- Error strings should not be capitalised
- In general it's not nice that this huge bunch of miscellaneous code fixes are part of this bug fix. They are good pieces, but not required to fix the bug this PR talks about. It's fine for now as the work is done already, but keep this in mind for future reference
| fs.Int32Var(&s.SafetyOptions.SafetyDown, "safety-down", s.SafetyOptions.SafetyDown, "Upper-limit minus safety-down value gives the lower-limit. This is the limits below which any temporarily frozen machineSet/machineDeployment object is unfrozen. lower-limit = desired + maxSurge (if applicable) + safetyUp - safetyDown.") | ||
|
|
||
| fs.DurationVar(&s.SafetyOptions.MachineSafetyOvershootingPeriod.Duration, "machine-safety-overshooting-period", s.SafetyOptions.MachineSafetyOvershootingPeriod.Duration, "Time period (in duration) used to poll for overshooting of machine objects backing a machineSet by safety controller.") | ||
| fs.DurationVar(&s.SafetyOptions.MachinePreserveTimeout.Duration, "machine-preserve-timeout", s.SafetyOptions.MachinePreserveTimeout.Duration, "Duration for which a failed machine should be preserved if it has the appropriate preserve annotation set.") |
There was a problem hiding this comment.
The issue description does not mention any new flag. A new flag like this is important enough to be mentioned as a release note
| klog.Errorf("Error annotating and setting PreserveExpiryTime on machine %q for auto-preservation: %v", machine.Name, err) | ||
| return nil, err |
There was a problem hiding this comment.
Returning here stops patching of further machines. Consider pooling all error messages and returning an aggregate error at the end of the loop
| // nodeTemplateChanged returns true if machine's nodeTemplate is changed. | ||
| func nodeTemplateChanged(machineset *v1alpha1.MachineSet, machine *v1alpha1.Machine) bool { |
There was a problem hiding this comment.
This func name is semantically incorrect. Generally a machine's nodeTemplate won't change but would rather get outdated and needs to be re-synced.
Consider names like nodeTemplateOutOfSync or machineNodeTemplateMismatch or feel free to choose another name that you feel is more accutare
| // configChanged returns true if machine's config is changed. | ||
| func configChanged(machineset *v1alpha1.MachineSet, machine *v1alpha1.Machine) bool { |
There was a problem hiding this comment.
Same as above, name is not accurate
| // classKindChanged returns true if machine's class.Kind is changed. | ||
| func classKindChanged(machineset *v1alpha1.MachineSet, machine *v1alpha1.Machine) bool { |
There was a problem hiding this comment.
This naming is not accurate too
| machineCurrentStatus := v1alpha1.CurrentStatus{ | ||
| Phase: v1alpha1.MachineFailed, | ||
| LastUpdateTime: metav1.Now(), | ||
| } |
There was a problem hiding this comment.
Does having this out and assigned to another var help much?
There was a problem hiding this comment.
Yes. I update the PreserveExpiryTime below, based on certain criteria. If there is a better way, I can change it.
| } else { | ||
| delete(clone.Annotations, machineutils.PreserveMachineAnnotationKey) | ||
| klog.V(3).Infof( | ||
| "Syncing machine %q 's annotation:%q=%q to its node %q 's annotation:%q=%q", |
There was a problem hiding this comment.
This is worded incorrectly. We sync the node's annotation to the machine
| PreserveExpiryTime: machine.Status.CurrentStatus.PreserveExpiryTime, | ||
| } | ||
| // check if preservation is needed for the failed machine | ||
| if val, shouldHandlePreservation := machineutils.GetPreserveAnnotationValue(node, machine); shouldHandlePreservation && val == machineutils.PreserveMachineAnnotationValueWhenFailed { | ||
| clone.Status.CurrentStatus.PreserveExpiryTime = &metav1.Time{Time: metav1.Now().Add(c.getEffectiveMachinePreserveTimeout(machine).Duration)} | ||
| } |
There was a problem hiding this comment.
This snippet could potentially overwrite existing PreserveExpiryTime on the machine that is set a line above
Although, @thiyyakat do you know why we might already have a PreserveExpiryTime on the machine? We enter this block only when the machine is in the Pending phase so I wonder if line 1142 is ever relevant
There was a problem hiding this comment.
Correct me if I am wrong @thiyyakat
Only for preserve=now PreserveExpiryTime is set else it is nil. I am setting PreserveExpiryTime only for preserve=when-failed, so they should not conflict.
| func (c *controller) updateMachineToFailedState(ctx context.Context, description string, machine, clone *v1alpha1.Machine) (bool, error) { | ||
| // Log the error message for machine failure | ||
| klog.Error(description) | ||
| node, _ := c.nodeLister.Get(machine.Annotations[v1alpha1.NodeLabelKey]) |
There was a problem hiding this comment.
Please don't ignore a potential error
There was a problem hiding this comment.
After offline discussions, we decided to log the error.
Signed-off-by: r4mek <vivek.ram688@gmail.com>
Signed-off-by: r4mek <vivek.ram688@gmail.com>
Signed-off-by: r4mek <vivek.ram688@gmail.com>
Signed-off-by: r4mek <vivek.ram688@gmail.com>
1fa4282 to
f28bbed
Compare
What this PR does / why we need it:
PreserveExpiryTimeon the machine if the machine has annotation:node.machine.sapcloud.io/preserve: "when-failed"and it transitions toFailedphase.PreserveExpiryTimeon the machine if the failed machine gets the annotation:node.machine.sapcloud.io/preserve: "auto-preserved"UpdateMachineWithRetries()from the lister cache, which may return a stale object.Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
All the miscellaneous code fix are much needed to fix the aforementioned bug without surfacing/introducing new bugs.
Release note: